﻿using System.Xml;
using System.Windows.Forms;
using SdmxMl.Common;

namespace SdmxMl.Structure
{
    /// <summary>
    /// CategorySchemeType describes the structure of a category scheme.
    /// This is a simple, levelled hierarchy. The scheme itself is given
    /// a human-readable name (which may be in multiple language-specific
    /// versions), and may optionally have a human-readable description
    /// (also in multiple, landuage-specific versions). Annotations may be
    /// provided in the Annotations element. The Category element represents
    /// a set of nested categories which describe a simple classification
    /// hierarchy. The CategoryScheme must have an agency specified in the
    /// agency attribute, and a unique ID provided for all of the category
    /// schemes of that agency in the id attribute. A version may also be
    /// supplied - if ommitted, the version is understood to be "1.0".
    /// If the isFinal attribute has a value of true, the category scheme
    /// is final and cannot be changed without versioning. All production
    /// category schemes must be final. The urn attribute holds a valid
    /// registry URN (see the SDMX Registry Specification). 
    /// If the isExternalReference attribute has a value of true, then the
    /// uri attribute must have a value which provides the location of a
    /// valid SDMX Structure message providing full details of the
    /// Category Scheme. Otherwise, all details must be provided here.
    /// The validFrom and validTo attributes provide inclusive dates for
    /// providing supplemental validity information about the version.
    /// </summary>
    public class CategorySchemeType : Artefact
    {
        #region properties

        private CategoryList categoryList;
        public CategoryList CategoryList
        {
            get { return categoryList; }
            set { categoryList = value; }
        }
        
        public override ArtefactRefTypedList ArtefactRefList
        {
            get
            {
                ArtefactRefTypedList list = new ArtefactRefTypedList();

                // Category can refers Metadataflow and dataflow
                FillFlowRef(this.CategoryList, list);

                return list;
            }
        }

        private void FillFlowRef(CategoryList catList, ArtefactRefTypedList list)
        {
            foreach (Category cat in catList)
            {
                foreach (DataFlowRef df in cat.DataFlowRefList)
                {
                    ArtefactRefTyped at = new ArtefactRefTyped(
                       SdmxMl.Manager.SdmxArtefactType.Dataflows,
                       df.FlowId, df.AgencyId, df.Version);
                    if (at.IsFilled && list.Contains(at.Type, at.FullIdent) == false)
                        list.Add(at);
                }

                foreach (MetaDataFlowRef mf in cat.MetaDataFlowRefList)
                {
                    ArtefactRefTyped at = new ArtefactRefTyped(
                       SdmxMl.Manager.SdmxArtefactType.Metadataflows,
                       mf.FlowId, mf.AgencyId, mf.Version);
                    if (at.IsFilled && list.Contains(at.Type, at.FullIdent) == false)
                        list.Add(at);
                }

                // Recurse
                FillFlowRef(cat.CategoryList, list);

            }
        }
        #endregion

        #region Constructor

        private void Init()
        {
            categoryList = new CategoryList(null);
        }

        public CategorySchemeType()
        {
            Init();
        }

        public CategorySchemeType(XmlNode nodeArtefact, SdmxNamespaceManager nsmgr)
            : base(nodeArtefact, nsmgr)
        {
            Init();
            string query ="./structure:Category";
            XmlNodeList nodeList = nodeArtefact.SelectNodes(query, nsmgr);
            if (nodeList.Count > 0)
            {
                foreach (XmlNode nd in nodeList)
                {
                    Category c = new Category(CategoryList, null, nd, nsmgr);
                    CategoryList.Add(c);
                }

            }
        }

        #endregion

        #region XML Serialize

        public override void WriteXmlInsider(XmlTextWriter xw)
        {
            foreach (Category cat in categoryList)
                cat.WriteXml(xw, "structure", "Category");
        }
        #endregion

        #region Tree
        public override TreeNode FillNode(TreeNode parentNode)
        {
            TreeNode t = base.FillNode(parentNode);
            TreeNode tc = new TreeNode(categoryList.ToString(), 1, 1);
            tc.Tag = categoryList;
            t.Nodes.Add(tc);
            foreach (Category c in categoryList)
                c.FillNode(tc);
            return t;
        }

        #endregion

        #region Artefact Type

        public override Manager.SdmxArtefactType ArType
        {
            get {return Manager.SdmxArtefactType.CategorySchemes; }
        }

        #endregion

    }
}
